/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../macro/head.h"
#include "../tools/head.h"
#include "../../../../xosbin/lib/include/lzma/head.h"
#include "lzma_impl.h"
#include "mgr.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos_compress
{
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static lzma_impl::ITEM_DATA xos_item_data;
    
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// 
	// 提供给7z的分配内存函数
	// 
	void *SzAlloc( ISzAllocPtr p, size_t size )
	{
		void * lpData = 0;
		lpData = mgr::alloc()->my_malloc( size );
		return lpData;
	}

	void SzFree( ISzAllocPtr p, void *address )
	{
		mgr::alloc()->my_free( address );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//

    int lzma_impl::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
		int ret = 0;
		xos_item_data.set_container( mgr::container() );
		item_ptr = &xos_item_data;
		return ret;
    }

	lzma_impl::lzma_impl()
	{
	}

	lzma_impl::~lzma_impl()
	{
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 

	int lzma_impl::init()
	{
		int ret = 0;
		return ret;
	}

	int lzma_impl::term()
	{
		int ret = 0;
		return ret;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 

	// 
	// 解压
	// 
	int lzma_impl::un_compress( char * lpszDest, int nDestLen, int * lpnDestLen, const char * lpszSrc, int nSrcLen )
	{
		using namespace xos_compress;
		using namespace std;

		int ret = 0;

		int nIntSize = sizeof( uint32_t );
		unsigned char * dest = (unsigned char *)lpszDest;
		size_t destLen = 0;	// 用取出来的原始长度，这样解压函数才不会出错
		const unsigned char *src = (const unsigned char *)( lpszSrc + LZMA_PROPS_SIZE + nIntSize );
		size_t srcLen = nSrcLen - LZMA_PROPS_SIZE - nIntSize;
		const unsigned char * props = (const unsigned char *)( lpszSrc + nIntSize );
		size_t outPropsSize = LZMA_PROPS_SIZE;
		ISzAlloc const my_alloc = { SzAlloc, SzFree };

		if( 0 == ret )
		{
			uint32_t uRawDataLen = 0;
			int pos = 0, len = nIntSize;
			ret = mgr::container()->box()->serial()->un_pack_int32( lpszSrc, &pos, &len, &uRawDataLen );
			if( 0 == ret )
			{
				destLen = uRawDataLen;
			}
		}

		if( 0 == ret )
		{
			ELzmaStatus status;
			ret = LzmaDecode( dest, &destLen, src, &srcLen, props, (unsigned)outPropsSize, LZMA_FINISH_ANY, &status, &my_alloc );
		}

		if( ( 0 == ret ) && lpnDestLen )
		{
			*lpnDestLen = (int)destLen;
		}

		return ret;
	}

	// 
	// 压缩
	// 
	int lzma_impl::compress( char * lpszDest, int nDestLen, int * lpnDestLen, const char * lpszSrc, int nSrcLen, bool bLast )
	{
		using namespace xos_compress;
		using namespace std;

		int ret = 0;

		int nIntSize = sizeof( uint32_t );
		unsigned char * dest = (unsigned char *)( lpszDest + LZMA_PROPS_SIZE + nIntSize );
		size_t destLen = nDestLen - LZMA_PROPS_SIZE - nIntSize;
		unsigned char * outProps = (unsigned char *)( lpszDest + nIntSize );
		size_t outPropsSize = LZMA_PROPS_SIZE;
		const unsigned char *src = (const unsigned char *)lpszSrc;
		size_t srcLen = nSrcLen;
		ISzAlloc const my_alloc = { SzAlloc, SzFree };

		if( 0 == ret )
		{
			int pos = 0, len = 0;
			int nLenLeft = nDestLen;
			ret = mgr::container()->box()->serial()->pack_int32( lpszDest, pos, &len, &nLenLeft, nSrcLen );
		}

		if( 0 == ret )
		{
			CLzmaEncProps props;
			LzmaEncProps_Init( &props );
			props.level = -1;
			props.dictSize = 0;
			props.lc = -1;
			props.lp = -1;
			props.pb = -1;
			props.fb = -1;
			props.numThreads = 1;
			ret = LzmaEncode( dest, &destLen, src, srcLen, &props, outProps, &outPropsSize, 0, NULL, &my_alloc, &my_alloc );
		}

		if( ( 0 == ret ) && lpnDestLen )
		{
			*lpnDestLen = (int)destLen + LZMA_PROPS_SIZE + nIntSize;
		}

		return ret;
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int lzma_impl::un_compress( xos_box::i_buf * pDestBuf, xos_box::i_buf * pSrcBuf )
    {
        int ret = 0;
        int nDestBufSize = 0, nDestLen = 0, nDestOutLen = 0, nSrcLen = 0;
        const char * lpszSrc = pSrcBuf->get_data( 0, 0, 0, &nSrcLen );
        char * lpszDest = pDestBuf->get_data( 0, 0, 0, &nDestLen );
        nDestBufSize = xos_box::i_buf::BUF_SIZE - nDestLen;
        ret = un_compress( lpszDest, nDestBufSize, &nDestOutLen, lpszSrc, nSrcLen );
        if( 0 == ret )
        {
            nDestLen = nDestLen + nDestOutLen;
            pDestBuf->set_len( nDestLen );
        }
        return ret;
    }

	int lzma_impl::compress( xos_box::i_buf * pDestBuf, xos_box::i_buf * pSrcBuf, bool bLast )
	{
		int ret = 0;
		int nDestBufSize = 0, nDestLen = 0, nDestOutLen = 0, nSrcLen = 0;
		const char * lpszSrc = pSrcBuf->get_data( 0, 0, 0, &nSrcLen );
		char * lpszDest = pDestBuf->get_data( 0, 0, 0, &nDestLen );
		nDestBufSize = xos_box::i_buf::BUF_SIZE - nDestLen;
		ret = compress( lpszDest, nDestBufSize, &nDestOutLen, lpszSrc, nSrcLen, bLast );
		if( 0 == ret )
		{
			nDestLen = nDestLen + nDestOutLen;
			pDestBuf->set_len( nDestLen );
		}
		return ret;
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int lzma_impl::un_compress( xos_box::i_list * pDestList, xos_box::i_list * pSrcList )
    {
        int ret = 0;

        xos_box::i_buf * pDest = 0;
        xos_box::i_buf * pSrc = 0;

        while( ( 0 == ret ) && ( pSrc = ( xos_box::i_buf * )pSrcList->front( 0 ) ) )
        {
			pDest = mgr::container()->box()->buf();
            ret = un_compress( pDest, pSrc );
            if( 0 == ret )
            {
                pDestList->push_back( pDest );
                pSrcList->pop_front();
                pDest = 0;
            }
            else
            {
                pSrc = 0;
            }
            xos_stl::release_interface( pDest );
            xos_stl::release_interface( pSrc );
        }

        return ret;
    }

    int lzma_impl::compress( xos_box::i_list * pDestList, xos_box::i_list * pSrcList )
    {
        int ret = 0;

        xos_box::i_buf * pDest = 0;
        xos_box::i_buf * pSrc = 0;

        while( ( 0 == ret ) && ( pSrc = ( xos_box::i_buf * )pSrcList->front( 0 ) ) )
        {
			pDest = mgr::container()->box()->buf();
            xos_box::i_buf * pEnd = ( xos_box::i_buf * )pSrcList->back( 0 );
            ret = compress( pDest, pSrc, pSrc == pEnd );
            if( 0 == ret )
            {
                pDestList->push_back( pDest );
                pSrcList->pop_front();
                pDest = 0;
            }
            else
            {
                pSrc = 0;
            }
            xos_stl::release_interface( pDest );
            xos_stl::release_interface( pSrc );
        }

        return ret;
    }

}
